using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;
using Evolution.Engine.Managers;
using Evolution.Engine.Cameras;
using Evolution.Engine.Objects;
using Evolution.Engine.GUI;
using Evolution.Engine.Interfaces;

namespace Evolution.Engine
{
    public delegate void Initialize();
    public delegate void Update(GameTime gameTime);

    /// <summary>
    /// The main Game Engine Class, this is the starting point for the engine, you instantiate this and it would,
    /// do the rest.
    /// </summary>
    public class GameEngine : Game
    {
        public event Initialize OnInitialize;
        public event Update OnUpdate;

        private static GameEngine _Instance;
        public static GameEngine Instance { get { if (_Instance == null) _Instance = new GameEngine(); return _Instance; } }

        public IServiceProvider Service { get { return _Instance.Services; } }
        public GraphicsDevice Device { get { return GameEngine.Instance.Graphics.GraphicsDevice; } }
        public GraphicsDeviceManager Graphics = null;
        public Fps Fps = new Fps();
        private IScript gameEngine = null;

        /// <summary>
        /// Public Constructor for the Game Engine
        /// </summary>
        public GameEngine()
        {
            Graphics = new GraphicsDeviceManager(this);
            CameraManager.Instance.Add(new FirstpersonCamera("FirstpersonCamera"));
        }

        /// <summary>
        /// Load Initial Resources needed for the management of the engine, subsequant resources will be loaded by
        /// the levels as they are required.
        /// </summary>
        /// <param name="loadAllContent"></param>
        protected override void LoadGraphicsContent(bool loadAllContent)
        {
            ShaderManager.Instance.LoadContent();
            SceneManager.Instance.CurrentScene.LoadContent();
            PlayerManager.Instance.LoadContent();
            EvolutionGuiSystem.Instance.LoadContent();

            if (gameEngine != null) gameEngine.Load();

            base.LoadGraphicsContent(loadAllContent);
        }

        /// <summary>
        /// Initialization of engine and Camera's.
        /// </summary>
        protected override void Initialize()
        {
            ResourceManager.Instance.LoadResources("Content/Resources.xml");
            gameEngine = ScriptManager.Instance.Get<IScript>("Content/GameEngine.script", "Scripts");

            if (OnInitialize != null) OnInitialize();
            CameraManager.Instance.ActiveCamera.SetViewport(Device.Viewport);
            EvolutionGuiSystem.Instance.Initialize();

            if (gameEngine != null) gameEngine.Initialize();

            base.Initialize();
        }

        /// <summary>
        /// The Engine Update routine called by XNA to update the current active scene.
        /// </summary>
        /// <param name="gameTime"></param>
        protected override void Update(GameTime gameTime)
        {
            if (gameEngine != null) gameEngine.Update(gameTime);

            InputManager.Instance.MouseHandled = false;
            InputManager.Instance.Update(gameTime);
            MouseManager.Instance.Update(gameTime);
            CameraManager.Instance.ActiveCamera.Update(gameTime);

            if (LevelManager.Instance.Level != null)
                LevelManager.Instance.Level.Update(gameTime);

            if (OnUpdate != null) OnUpdate(gameTime);

            Fps.Update(gameTime);

#if(DEBUG)            
            TextManager.Instance.Write("Default", Fps.ToString(), new Vector2(10, 10), Color.Yellow);

            if( PlayerManager.Instance.Player != null )
                TextManager.Instance.Write("Default", "Player : " + PlayerManager.Instance.Player.Position.ToString(), new Vector2(10, 25), Color.White);
#endif
            
            EvolutionGuiSystem.Instance.Update(gameTime);
            EnvironmentManager.Instance.Update(gameTime);
            SceneManager.Instance.CurrentScene.Update(gameTime);
            PlayerManager.Instance.Update(gameTime);
            LightManager.Instance.Update(gameTime);

            base.Update(gameTime);
        }

        /// <summary>
        /// here is where the magic hapens to render to the back buffer for drawing the current scene.
        /// 
        /// 1. Render the 3D Scene
        /// 2. Render any text displayed in the 3D Scene
        /// 2. Render any GUI visible
        /// 3. Lastly render any overlay / GUI Text batched
        /// </summary>
        /// <param name="gameTime"></param>
        protected override void Draw(GameTime gameTime)
        {
            Graphics.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.DarkBlue, 1.0f, 0);

            if (gameEngine != null) gameEngine.Draw(gameTime);

            if (LevelManager.Instance.Level != null)
                LevelManager.Instance.Level.Draw(gameTime);

            SceneManager.Instance.CurrentScene.Draw(gameTime);
            PlayerManager.Instance.Render(gameTime);
            EvolutionGuiSystem.Instance.Draw(gameTime);
            TextManager.Instance.Draw(gameTime);
            MouseManager.Instance.Draw(gameTime);
            
            base.Draw(gameTime);
        }
    }
}
